package com.atguigu.yygh.hosp.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.yygh.exception.YYGHException;
import com.atguigu.yygh.hosp.repository.ScheduleRepository;
import com.atguigu.yygh.hosp.service.DepartmentService;
import com.atguigu.yygh.hosp.service.HospitalService;
import com.atguigu.yygh.hosp.service.ScheduleService;
import com.atguigu.yygh.model.hosp.BookingRule;
import com.atguigu.yygh.model.hosp.Department;
import com.atguigu.yygh.model.hosp.Hospital;
import com.atguigu.yygh.model.hosp.Schedule;
import com.atguigu.yygh.vo.hosp.BookingScheduleRuleVo;
import com.atguigu.yygh.vo.hosp.ScheduleOrderVo;
import javafx.scene.control.Pagination;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/*==========================================
      时 间:   2022-04-19
      讲 师:   刘  辉
      描 述:   尚硅谷教学团队
 ==========================================*/
@Service
public class ScheduleServiceImpl implements ScheduleService {
    @Autowired
    private ScheduleRepository scheduleRepository;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private HospitalService hospitalService;
    @Autowired
    private DepartmentService departmentService;

    @Override
    public void save(Map<String, Object> stringObjectMap) {
        Schedule schedule = JSONObject.parseObject(JSONObject.toJSONString(stringObjectMap), Schedule.class);
        String hoscode = schedule.getHoscode();
        String depcode = schedule.getDepcode();
        String hosScheduleId = schedule.getHosScheduleId();

        Schedule mongoSchedule=scheduleRepository.findByHoscodeAndDepcodeAndHosScheduleId(hoscode,depcode,hosScheduleId);

        if(mongoSchedule == null){
            schedule.setCreateTime(new Date());
            schedule.setUpdateTime(new Date());
            schedule.setIsDeleted(0);
            scheduleRepository.save(schedule);
        }else{
            schedule.setCreateTime(mongoSchedule.getCreateTime());
            schedule.setUpdateTime(new Date());
            schedule.setIsDeleted(mongoSchedule.getIsDeleted());
            schedule.setId(mongoSchedule.getId());
            scheduleRepository.save(schedule);
        }

    }

    @Override
    public Page<Schedule> shedulePage(Map<String, Object> stringObjectMap) {
        String hoscode = (String)stringObjectMap.get("hoscode");
        String page = (String)stringObjectMap.get("page");
        String limit = (String)stringObjectMap.get("limit");
        Schedule schedule=new Schedule();
        schedule.setHoscode(hoscode);

        Example<Schedule> scheduleExample=Example.of(schedule);

        PageRequest pageRequest = PageRequest.of(Integer.parseInt(page) - 1, Integer.valueOf(limit));

        return scheduleRepository.findAll(scheduleExample,pageRequest);
    }

    @Override
    public Map<String, Object> getSchedulePage(String hoscode, String depcode, Integer page, Integer limit) {

        Map<String,Object> resultMap=new HashMap<String,Object>();

        //第一个参数：Aggregation:聚合条件
        //第二个参数：inputType:表示输入类型，
        //第三个参数:outputType:表示输出类型，
        Criteria criteria=Criteria.where("hoscode").is(hoscode).and("depcode").is(depcode);


        Aggregation aggregation=Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("workDate")
                           .first("workDate").as("workDate")
                           .count().as("docCount")
                           .sum("reservedNumber").as("reservedNumber")
                           .sum("availableNumber").as("availableNumber"),
                Aggregation.sort(Sort.Direction.ASC,"workDate"),
                Aggregation.skip((page-1)*limit),
                Aggregation.limit(limit)
        );
        AggregationResults<BookingScheduleRuleVo> aggregate = mongoTemplate.aggregate(aggregation, Schedule.class, BookingScheduleRuleVo.class);
        List<BookingScheduleRuleVo> mappedResults = aggregate.getMappedResults();
        for (BookingScheduleRuleVo mappedResult : mappedResults) {
            Date workDate = mappedResult.getWorkDate();
            mappedResult.setDayOfWeek(getDayOfWeek(new DateTime(workDate)));
        }

        Aggregation aggregation1=Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("workDate").first("workDate").as("workDate")
        );
        AggregationResults<BookingScheduleRuleVo> aggregate1 = mongoTemplate.aggregate(aggregation1, Schedule.class, BookingScheduleRuleVo.class);
        List<BookingScheduleRuleVo> mappedResults1 = aggregate1.getMappedResults();

        resultMap.put("list",mappedResults);
        resultMap.put("total",mappedResults1.size());

        //其他基础数据
        Hospital hosptialInfo = hospitalService.getHosptialInfo(hoscode);
        Map<String, String> baseMap = new HashMap<>();
        baseMap.put("hosname",hosptialInfo.getHosname());
        resultMap.put("baseMap",baseMap);
        return resultMap;
    }

    @Override
    public List<Schedule> getScheduleDetail(String hoscode, String depcode, String workdate) {
        List<Schedule> scheduleList= scheduleRepository.findByHoscodeAndDepcodeAndWorkDate(hoscode,depcode,new DateTime(workdate).toDate());

        for (Schedule schedule : scheduleList) {
            this.packageSchedule(schedule);
        }

        return scheduleList;
    }


    @Override
    public Map<String, Object> getSchedulePageByCondition(Integer page, Integer limit, String hoscode, String depcode) {

        //1.先根据医院编号查询医院信息
        Hospital hosptialInfo = hospitalService.getHosptialInfo(hoscode);
        if(hosptialInfo == null){
            throw new YYGHException(2001,"没有该医院信息");
        }

        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Date> result1 = this.getDateList(page, limit, hosptialInfo);


        List<Date> records = result1.getRecords();

        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("hoscode").is(hoscode).and("depcode").is(depcode).and("workDate").in(records)),
                Aggregation.group("workDate").first("workDate").as("workDate")
                        .count().as("docCount")
                        .sum("reservedNumber").as("reservedNumber")
                        .sum("availableNumber").as("availableNumber"),
                Aggregation.sort(Sort.Direction.ASC, "workDate"));

        //schedule集合查询排班信息
        AggregationResults<BookingScheduleRuleVo> aggregate = mongoTemplate.aggregate(aggregation, Schedule.class, BookingScheduleRuleVo.class);
        //聚合列表数据
        List<BookingScheduleRuleVo> mappedResults = aggregate.getMappedResults();
        // 2021-06-15
        Map<Date, BookingScheduleRuleVo> groupMap = mappedResults.stream().collect(Collectors.toMap(BookingScheduleRuleVo::getWorkDate, BookingScheduleRuleVo -> BookingScheduleRuleVo));
        int size = records.size();

        List<BookingScheduleRuleVo> bookingScheduleRuleVoList=new ArrayList<BookingScheduleRuleVo>();

        for (int i = 0; i < size; i++) {
            Date date = records.get(i);
            BookingScheduleRuleVo bookingScheduleRuleVo = groupMap.get(date);
            if(bookingScheduleRuleVo == null){
                bookingScheduleRuleVo=new BookingScheduleRuleVo();
                bookingScheduleRuleVo.setDocCount(0);
                bookingScheduleRuleVo.setReservedNumber(0);
                bookingScheduleRuleVo.setAvailableNumber( -1);
                bookingScheduleRuleVo.setStatus(1);
            }
            //信息
            bookingScheduleRuleVo.setWorkDate(date);
            bookingScheduleRuleVo.setDayOfWeek(this.getDayOfWeek(new DateTime(date)));


            bookingScheduleRuleVo.setStatus(0);

            //第一页第一条
            if(page == 1 && i == 0){
                String stopTime = hosptialInfo.getBookingRule().getStopTime();
                DateTime dateTime = this.getDateTime(date, stopTime);
                if(dateTime.isBeforeNow()){
                    bookingScheduleRuleVo.setStatus(-1);
                }
            }

            if(page == result1.getPages() && i == size-1){
                bookingScheduleRuleVo.setStatus(1);
            }


            bookingScheduleRuleVoList.add(bookingScheduleRuleVo);
        }


        HashMap<String, Object> stringObjectHashMap = new HashMap<>();

        //可预约日期规则数据
        stringObjectHashMap.put("bookingScheduleList", bookingScheduleRuleVoList);
        stringObjectHashMap.put("total", result1.getTotal());

        //其他基础数据
         Map<String, String> baseMap = new HashMap<>();
        //医院名称
        baseMap.put("hosname", hospitalService.getHosptialInfo(hoscode).getHosname());
        //科室
        Department department =departmentService.findByHoscodeAndDepcode(hoscode, depcode);
        //大科室名称
        baseMap.put("bigname", department.getBigname());
        //科室名称
        baseMap.put("depname", department.getDepname());
        //月
        baseMap.put("workDateString", new DateTime().toString("yyyy年MM月"));
        //放号时间
        baseMap.put("releaseTime", hosptialInfo.getBookingRule().getReleaseTime());
        //停号时间
        baseMap.put("stopTime", hosptialInfo.getBookingRule().getStopTime());
         stringObjectHashMap.put("baseMap", baseMap);
        return stringObjectHashMap;
    }


    @Override
    public Schedule getScheduleById(String scheduleId) {
        Schedule schedule = scheduleRepository.findById(scheduleId).get();
        this.packageSchedule(schedule);
        return schedule;
    }


    @Override
    public ScheduleOrderVo getScheduleOrderVoById(String scheduleId) {
       Schedule schedule= scheduleRepository.findById(scheduleId).get();
       ScheduleOrderVo scheduleOrderVo=new ScheduleOrderVo();
       BeanUtils.copyProperties(schedule,scheduleOrderVo);
        Hospital hosptialInfo = hospitalService.getHosptialInfo(schedule.getHoscode());
        scheduleOrderVo.setHosname(hosptialInfo.getHosname());
        scheduleOrderVo.setDepname(departmentService.findByHoscodeAndDepcode(schedule.getHoscode(),schedule.getDepcode()).getDepname());
        scheduleOrderVo.setReserveDate(schedule.getWorkDate());
        scheduleOrderVo.setReserveTime(schedule.getWorkTime());

        DateTime dateTime1 = this.getDateTime(new DateTime(schedule.getWorkDate()).plusDays(hosptialInfo.getBookingRule().getQuitDay()).toDate(), hosptialInfo.getBookingRule().getQuitTime());

        scheduleOrderVo.setQuitTime(dateTime1.toDate());
        //当天停止挂号时间
        DateTime stopTime = this.getDateTime(schedule.getWorkDate(), hosptialInfo.getBookingRule().getStopTime());
        scheduleOrderVo.setStopTime(stopTime.toDate());

        return scheduleOrderVo;
    }

    @Override
    public boolean update(String scheduleId, Integer availableNumber) {
        Schedule schedule= scheduleRepository.findById(scheduleId).get();
        schedule.setAvailableNumber(availableNumber);
        schedule.setUpdateTime(new Date());
        scheduleRepository.save(schedule);
        return true;
    }

    @Override
    public void cancel(String scheduleId) {
        Schedule schedule= scheduleRepository.findByHosScheduleId(scheduleId);
        schedule.setAvailableNumber(schedule.getAvailableNumber()+1);
        scheduleRepository.save(schedule);
    }

    //获取时间列表的数据
    private com.baomidou.mybatisplus.extension.plugins.pagination.Page<Date> getDateList(Integer page, Integer limit, Hospital hosptialInfo) {
        BookingRule bookingRule = hosptialInfo.getBookingRule();
        Integer cycle = bookingRule.getCycle();
        //此时此刻的时间和
        String releaseTime = bookingRule.getReleaseTime();
        DateTime dateTime = this.getDateTime(new Date(), releaseTime);

        if(dateTime.isBeforeNow()){
            cycle=cycle+1;
        }

        List<Date> list =new ArrayList<Date>();

        for(int i=0;i<cycle;i++){
            DateTime dateTime1 = new DateTime().plusDays(i);
            String string = dateTime1.toString("yyyy-MM-dd");
            list.add(new DateTime(string).toDate());
        }

        int start = (page-1)*limit;
        int end = start+limit;
        if(end > list.size()){
            end=list.size();
        }

        List<Date> finalList =new ArrayList<Date>();
        for(int i=start;i<end;i++){
            finalList.add( list.get(i));
        }

        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Date> page1 = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<Date>(page, limit, list.size());
        page1.setRecords(finalList);
        return page1;
    }
    /**
     * 将Date日期（yyyy-MM-dd HH:mm）转换为DateTime
     */
    private DateTime getDateTime(Date date, String timeString) {
        String dateTimeString = new DateTime(date).toString("yyyy-MM-dd") + " "+ timeString;
        DateTime dateTime = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm").parseDateTime(dateTimeString);
        return dateTime;
    }



    //封装排班详情其他值 医院名称、科室名称、日期对应星期
    private void packageSchedule(Schedule schedule) {
        //设置医院名称
        schedule.getParam().put("hosname",hospitalService.getHosptialInfo(schedule.getHoscode()).getHosname());
        //设置科室名称
        schedule.getParam().put("depname",departmentService.findByHoscodeAndDepcode(schedule.getHoscode(),schedule.getDepcode()).getDepname());
        //设置日期对应星期
        schedule.getParam().put("dayOfWeek",this.getDayOfWeek(new DateTime(schedule.getWorkDate())));
    }

    /**
     * 根据日期获取周几数据
     * @param dateTime
     * @return
     */
    private String getDayOfWeek(DateTime dateTime) {
        String dayOfWeek = "";
        switch (dateTime.getDayOfWeek()) {
            case DateTimeConstants.SUNDAY:
                dayOfWeek = "周日";
                break;
            case DateTimeConstants.MONDAY:
                dayOfWeek = "周一";
                break;
            case DateTimeConstants.TUESDAY:
                dayOfWeek = "周二";
                break;
            case DateTimeConstants.WEDNESDAY:
                dayOfWeek = "周三";
                break;
            case DateTimeConstants.THURSDAY:
                dayOfWeek = "周四";
                break;
            case DateTimeConstants.FRIDAY:
                dayOfWeek = "周五";
                break;
            case DateTimeConstants.SATURDAY:
                dayOfWeek = "周六";
            default:
                break;
        }
        return dayOfWeek;
    }

}
